<?php
/**
 * Created by PhpStorm.
 * User: lee
 * Date: 2018/11/20
 * Time: 3:31 PM
 */

namespace Biz\model\eventlog;

use Doraemon\pockets\publicTrait;
use Medoo\Medoo;
use Medoo\Raw;

/**
 *
 * @author lee
 *
 */
class TransactionLog extends \Doraemon\pockets\datebase\BaseDbModel
{
    use publicTrait\CheckConstants;

    const _CONFIG_FILE_ = 'db_eventlog';

    const _CONFIG_SELECT_ = 'db_event_log';

    const _DATABASE_ = 'biz_event_log';

    const _TABLE_NAME = 'transaction_log';

    const _CONSTANT_PREFIX = "BIZ_PREFIX_";


    //状态字
    const STATUS_NORMAL = 0;
    const STATUS_EXECED = 1;
    const STATUS_HAND_PAUSE = 3;
    const STATUS_SYS_PAUSE = 4;
    const STATUS_DELETE = 9;


    //支持的业务前缀
    const BIZ_PREFIX_EVENT = 'event';

    public static function initExecSlot($bizId, $slots = [], $addTime = '', $data = '')
    {

        $data = [
            'bizid' => $bizId,
            'data' => $data,
            'addtime' => date('Y-m-d H:i:s')
        ];

        if (!empty($addTime)) {
            $data['addtime'] = $addTime;
        }

        if (!empty($slots)) {
            $slots[] = 'main';
            $result = self::action(function () use ($data, $slots) {
                foreach ($slots as $slot) {
                    if ($slot == 'main') {
                        $data['mcounter'] = count($slots) - 1;
                        $data['retries'] = -1;
                    } else {
                        $data['mcounter'] = 1;
                    }
                    $data['slot'] = $slot;
                    self::insert($data);
                }

                return true;
            });

            return $result;

        }

        return false;

    }

    public static function execMainSlotSuccess($bizId)
    {
        $execTime = date('Y-m-d H:i:s');
        //标记main槽执行
        $result = self::update([
            'data' => self::concatData("retries:成功执行 $execTime"),
            'last_uptime' => $execTime,
            'succ_exectime' => $execTime,
            'status' => self::STATUS_EXECED
        ], [
            'bizid' => $bizId,
            'slot' => 'main',
            'status' => self::STATUS_NORMAL
        ]);
    }


    public static function execSlotOnlyOnce($bizId, $slot)
    {
        $execTime = date('Y-m-d H:i:s');

        //标记任务槽执行
        $result = self::update([
            'acounter[+]' => 1,
            'data' => self::concatData("retries:成功执行 $execTime"),
            'last_uptime' => $execTime,
            'succ_exectime' => $execTime,
            'status' => self::STATUS_EXECED
        ], [
            'bizid' => $bizId,
            'slot' => $slot,
            'status' => self::STATUS_NORMAL
        ]);

        if (!empty($result) && is_object($result)) {
            if ($result->rowCount() == 0) {
                return false;
            }
        }

        //标记main槽执行
        $result = self::update([
            'acounter[+]' => 1,
            'data' => self::concatData("retries:$slot 成功执行 $execTime"),
            'last_uptime' => $execTime,
        ], [
            'bizid' => $bizId,
            'slot' => 'main',
            'status' => self::STATUS_NORMAL
        ]);

        return true;
    }

    //标注一个任务执行因达到极限而暂停执行
    public static function execSlotSysPause($bizId, $slot)
    {
        $execTime = date('Y-m-d H:i:s');
        $result = self::update(['data' => self::concatData("retries:异常暂停 $execTime"), 'last_uptime' => $execTime, 'status' => self::STATUS_SYS_PAUSE], [
            'bizid' => $bizId,
            'slot' => $slot,
        ]);

        if (!empty($result) && is_object($result)) {
            if ($result->rowCount() > 0) {
                return true;
            }
        }
    }

    //一个任务因为重试而被标注
    public static function execSlotRetryMark($bizId, $slot)
    {
        $execTime = date('Y-m-d H:i:s');
        $result = self::update(['data' => self::concatData("retries:一次尝试 $execTime"), 'retries[+]' => 1, 'last_uptime' => $execTime], [
            'bizid' => $bizId,
            'slot' => $slot,
        ]);

        if (!empty($result) && is_object($result)) {
            if ($result->rowCount() > 0) {
                return true;
            }
        }


    }

    //一个任务因为等待而被标注
    public static function execSlotPauseMark($bizId, $slot, $data)
    {
        $execTime = date('Y-m-d H:i:s');

        $result = self::update(['data' => self::concatData($data), "last_uptime" => $execTime], [
            'bizid' => $bizId,
            'slot' => $slot,
            'status' => self::STATUS_NORMAL
        ]);

        if (!empty($result) && is_object($result)) {
            if ($result->rowCount() > 0) {
                return true;
            }
        }

        throw new \Exception('执行失败');

    }

    //一个任务因为异常而被标注
    public static function execSlotExceptionMark($bizId, $slot, $data)
    {
        $execTime = date('Y-m-d H:i:s');

        $result = self::update(['data' => self::concatData($data), "last_uptime" => $execTime], [
            'bizid' => $bizId,
            'slot' => $slot,
        ]);

        if (!empty($result) && is_object($result)) {
            if ($result->rowCount() > 0) {
                return true;
            }
        }


    }

    public static function getSysPauseSlotInfos($bizId)
    {
        $infoList = self::select(['bizid', 'slot', 'status'], ['bizid' => $bizId, 'status' => self::STATUS_SYS_PAUSE]);

        return $infoList;
    }

    public static function getSlotInfo($bizId, $slot)
    {
        $info = self::get('*', ['bizid' => $bizId, 'slot' => $slot]);

        self::formatInfo($info);

        return $info;
    }

    public static function getFirstSlotInfo($bizId)
    {
        $info = self::get('*', ['bizid' => $bizId]);

        return $info;
    }

    private static function formatInfo(&$info)
    {
        if (!empty($info)) {
            $info['data'] = !empty($info['data']) ? json_decode($info['data'], true) : [];
        }
    }

    private static function concatData($data = '')
    {
        return Medoo::raw("concat_ws('\n----------------------------------------------\n',data,'$data')");
    }


    public static function genBizId($prefix, $key)
    {
        if (self::checkConstants(self::_CONSTANT_PREFIX, $prefix)) {
            return $prefix . '-' . $key;
        }

        return null;

    }

    public static function countNonDoneSlots($bizId)
    {
        return self::count(['bizid' => $bizId, 'status' => [self::STATUS_NORMAL]]);
    }


}

